home *** CD-ROM | disk | FTP | other *** search
/ Atari Mega Archive 1 / Atari Mega Archive - Volume 1.iso / mint / lib / mntlib44.zoo / mntlib / do_stat.c < prev    next >
C/C++ Source or Header  |  1994-03-01  |  6KB  |  233 lines

  1. /*
  2.  * stat, fstat, lstat emulation for TOS
  3.  * written by Eric R. Smith and placed in the public domain
  4.  */
  5.  
  6. #include <limits.h>
  7. #include <types.h>
  8. #include <stat.h>
  9. #include <ctype.h>
  10. #include <errno.h>
  11. #include <osbind.h>
  12. #include <mintbind.h>
  13. #include <string.h>
  14. #include <time.h>
  15. #include <unistd.h>
  16. #include <support.h>
  17. #include <ioctl.h>    /* for FSTAT */
  18. #include "lib.h"
  19.  
  20. extern int __mint;
  21.  
  22. extern ino_t __inode;
  23.  
  24. /* for backwards compatibilty: if nonzero, files are checked to see if
  25.  * they have the TOS executable magic number in them
  26.  */
  27.  
  28. int    _x_Bit_set_in_stat = 0;
  29.  
  30. /* date for files (like root directories) that don't have one */
  31. #define OLDDATE _unixtime(0,0)
  32.  
  33. /*
  34.  * common routine for stat() and lstat(); if "lflag" is 0, then symbolic
  35.  * links are automatically followed (like stat), if 1 then they are not
  36.  * (like lstat)
  37.  */
  38.  
  39. __EXTERN int _do_stat __PROTO((const char *_path, struct stat *st, int lflag));
  40.  
  41. int
  42. _do_stat(_path, st, lflag)
  43.     const char *_path;
  44.     struct stat *st;
  45.     int lflag;
  46. {
  47.     long    r;
  48.     _DTA    *olddta;
  49.     int    nval;
  50.     char    path[PATH_MAX];
  51.     char    *ext, drv;
  52.     int    fd;
  53.     short    magic;
  54.     _DTA    d;
  55.     int    isdot = 0;
  56.  
  57.     if (!_path) {
  58.         errno = EFAULT;
  59.         return -1;
  60.     }
  61.  
  62. /*
  63.  * _unx2dos returns 1 for device names (like /dev/con)
  64.  */
  65.     nval = _unx2dos(_path, path);
  66.  
  67. /* for MiNT 0.9 and up, we use the built in stat() call */
  68.     if (__mint >= 9) {
  69.         r = Fxattr(lflag, path, st);
  70.         if (r) {
  71.             if ((r == -EPATH) && _enoent(path)) {
  72.                 r = -ENOENT;
  73.             }
  74.             errno = (int) -r;
  75.             return -1;
  76.         }
  77.         __UNIXTIME(st->st_mtime);
  78.         __UNIXTIME(st->st_atime);
  79.         __UNIXTIME(st->st_ctime);
  80.     /* Most versions of Unix count in 512 byte blocks */
  81.         st->st_blocks = (st->st_blocks * st->st_blksize) / 512;
  82.     /* if we hit a symbolic link, try to get its size right */
  83.         if (lflag && ((st->st_mode & S_IFMT) == S_IFLNK)) {
  84.             char buf[PATH_MAX + 1];
  85.             char buf1[PATH_MAX + 1];
  86.             r = Freadlink(PATH_MAX, buf, path);
  87.             if (r < 0)
  88.               {
  89.                 errno = (int) -r;
  90.                 return -1;
  91.               }
  92.             buf[PATH_MAX] = 0;
  93.             _dos2unx (buf, buf1);
  94.             st->st_size = strlen (buf1);
  95.         }
  96.         return 0;
  97.     }
  98.  
  99. /* otherwise, check to see if we have a name like CON: or AUX: */
  100.     if (nval == 1) {
  101.         st->st_mode = S_IFCHR | 0600;
  102.         st->st_attr = 0;
  103.         st->st_ino = ++__inode;
  104.         st->st_rdev = 0;
  105.         st->st_mtime = st->st_ctime = st->st_atime = 
  106.             time((time_t *)0) - 2;
  107.         st->st_dev = 0;
  108.         st->st_nlink = 1;
  109.         st->st_uid = geteuid();
  110.         st->st_gid = getegid();
  111.         st->st_size = st->st_blocks = 0;
  112.         st->st_blksize = 1024;
  113.         return 0;
  114.     }
  115.  
  116. /* A file name: check for root directory of a drive */
  117.     if (path[0] == '\\' && path[1] == 0) {
  118.         drv = Dgetdrv() + 'A';
  119.         goto rootdir;
  120.     }
  121.  
  122.     if ( ((drv = path[0]) != 0) && path[1] == ':' &&
  123.          (path[2] == 0 || (path[2] == '\\' && path[3] == 0)) ) {
  124. rootdir:
  125.         st->st_mode = S_IFDIR | 0755;
  126.         st->st_attr = FA_DIR;
  127.         st->st_dev = isupper(drv) ? drv - 'A' : drv - 'a';
  128.         st->st_ino = 2;
  129.         st->st_mtime = st->st_ctime = st->st_atime = OLDDATE;
  130.         goto fill_dir;
  131.     }
  132.  
  133. /* forbid wildcards in path names */
  134.     if (index(path, '*') || index(path, '?')) {
  135.         errno = ENOENT;
  136.         return -1;
  137.     }
  138.  
  139. /* OK, here we're going to have to do an Fsfirst to get the date */
  140. /* NOTE: Fsfirst(".",-1) or Fsfirst("..",-1) both fail under TOS,
  141.  * so we kludge around this by using the fact that Fsfirst(".\*.*"
  142.  * or "..\*.*" will return the correct file first (except, of course,
  143.  * in root directories :-( ).
  144.  * NOTE2: Some versions of TOS don't like Fsfirst("RCS\\", -1) either,
  145.  * so we do the same thing if the path ends in '\\'.
  146.  */
  147.  
  148. /* find the end of the string */
  149.     for (ext = path; ext[0] && ext[1]; ext++) ;
  150.  
  151. /* add appropriate kludge if necessary */
  152.     if (*ext == '.' && (ext == path || ext[-1] == '\\' || ext[-1] == '.')) {
  153.         isdot = 1;
  154.         strcat(path, "\\*.*");
  155.     } else if (*ext == '\\') {
  156.         isdot = 1;
  157.         strcat(path, "*.*");
  158.     }
  159.     olddta = Fgetdta();
  160.     Fsetdta(&d);
  161.     r = Fsfirst(path, 0xff);
  162.     Fsetdta(olddta);
  163.     if (r < 0) {
  164.         if (isdot && r == -ENOENT) goto rootdir;
  165.         errno = (int) -r;
  166.         return -1;
  167.     }    
  168.  
  169.     if (isdot && ((d.dta_name[0] != '.') || (d.dta_name[1]))) {
  170.         goto rootdir;
  171.     }
  172.  
  173.     st->st_mtime = st->st_ctime = st->st_atime =
  174.         _unixtime(d.dta_time, d.dta_date);
  175.     if (((drv = *path) != 0) && path[1] == ':')
  176.         st->st_dev = toupper(drv) - 'A';
  177.     else
  178.         st->st_dev = Dgetdrv();
  179.  
  180.     st->st_ino = __inode++;
  181.     st->st_attr = d.dta_attribute;
  182.     if (__mint && st->st_dev == ('Q' - 'A'))
  183.             st->st_mode = 0644 | S_IFIFO;
  184.     else {
  185.         st->st_mode = 0644 | (st->st_attr & FA_DIR ?
  186.                   S_IFDIR | 0111 : S_IFREG);
  187.     }
  188.  
  189.     if (st->st_attr & FA_RDONLY)
  190.         st->st_mode &= ~0222;    /* no write permission */
  191.     if (st->st_attr & FA_HIDDEN)
  192.         st->st_mode &= ~0444;    /* no read permission */
  193.  
  194. /* check for a file with an executable extension */
  195.     ext = strrchr(_path, '.');
  196.     if (ext) {
  197.         if (!strcmp(ext, ".ttp") || !strcmp(ext, ".prg") ||
  198.             !strcmp(ext, ".tos") || !strcmp(ext, ".g") ||
  199.             !strcmp(ext, ".sh")     || !strcmp(ext, ".bat")) {
  200.             st->st_mode |= 0111;
  201.         }
  202.     }
  203.     if ( (st->st_mode & S_IFMT) == S_IFREG) {
  204.         if (_x_Bit_set_in_stat) {
  205.             if ((fd = (int) Fopen(path,0)) < 0) {
  206.                 errno = -fd;
  207.                 return -1;
  208.             }
  209.             magic = 0;
  210.             (void)Fread(fd,2,(char *)&magic);
  211.             (void)Fclose(fd);
  212.             if (magic == 0x601A    /* TOS executable */
  213.                 || magic == 0x2321) /* "#!" shell file */
  214.                 st->st_mode |= 0111;
  215.         }
  216.         st->st_size = d.dta_size;
  217.     /* in Unix, blocks are measured in 512 bytes */
  218.         st->st_blocks = (st->st_size + 511) / 512;
  219.         st->st_nlink = 1; /* we dont have hard links */
  220.     } else {
  221. fill_dir:
  222.         st->st_size = 1024;
  223.         st->st_blocks = 2;
  224.         st->st_nlink = 2;    /* "foo" && "foo/.." */
  225.     }
  226.  
  227.     st->st_rdev = 0;
  228.     st->st_uid = geteuid();    /* the current user owns every file */
  229.     st->st_gid = getegid();
  230.     st->st_blksize = 1024;
  231.     return 0;
  232. }
  233.